package com.rd.sys.common.fileexport;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import baseproj.common.exception.BaseServiceException;
import baseproj.common.mybatis.page.PageParameter;

import com.rd.sys.common.base.CommonConstants;
import com.rd.sys.common.fileexport.inter.ExportOperator;
import com.rd.sys.dto.commmon.base.BaseDto;
import com.rd.sys.dto.commmon.enums.ExportEnum;

/**
 * 文件导出处理类
 */
public class ExportFile {
    /** The Constant logger. */
    private static final Logger logger = LoggerFactory.getLogger(ExportFile.class);

    /**
     * 执行导出操作
     * 
     * @param type
     *            当前导出模块类型
     * @param dto
     *            导出数据查询条件
     * @return the 导出缓存文件的全路径名称
     * @throws BaseServiceException
     *             the base service exception
     * @throws Exception
     *             the exception
     */
    public static File execute(ExportEnum.Type type, BaseDto dto) throws BaseServiceException, Exception {
        /** 1. 生成导出文件 */
        File exportFile = GenerateFile(type.getCode());

        /** 2. 预处理,生成表头 */
        preProcess(type.getCode(), exportFile);

        /** 3. 实际处理,查询并写入数据 */
        process(type.getCode(), exportFile, dto);

        return exportFile;
    }

    /**
     * 预处理(生成表头)
     * 
     * @param type
     */
    public static void preProcess(String type, File exportFile) {
        try {
            /** 1.读取配置文件 */
            ParseExportXML xml = ParseExportXML.getExportXml();
            HashMap<?, ?> map = xml.getData(type);
            if (map == null) {
                logger.error("not find config file!");
                throw new ExportOperatorException(ExportOperatorException.TYPE_NOT_FIND_ERROR);
            }

            /** 2.获取表头,并写入 */
            String head = map.get(CommonConstants.ExportConstants.EXPORT_CONFIG_FILE_NODE_HEAD).toString();
            head = head.replaceAll(CommonConstants.ExportConstants.EXPORT_CONFIG_FILE_HEAD_SPLIT_SIGN,
                    CommonConstants.ExportConstants.EXPORT_FILE_SPLIT_SIGN); // 替换分隔符为导出文件要求的分隔符
            writeFileHead(exportFile, head);
        } catch (Exception ex) {
            logger.error("write export head error", ex);
            throw new ExportOperatorException(ExportOperatorException.WRITE_HEAD_ERROR);
        }

    }

    /**
     * 实际处理(写入导出数据)
     * 
     * @param type
     * @param exportFile
     */
    public static void process(String type, File exportFile, BaseDto dto) {
        /** 1.获取数据读取对象 */
        ExportOperator operator = null;
        try {
            ParseExportXML xml = ParseExportXML.getExportXml();
            HashMap<?, ?> map = xml.getData(type);
            String className = map.get(CommonConstants.ExportConstants.EXPORT_CONFIG_FILE_NODE_OPERATOR).toString();
            // 获取配置的操作类,通过反射实例化
            operator = (ExportOperator) Class.forName(className).newInstance();
        } catch (Exception ex) {
            throw new ExportOperatorException(ExportOperatorException.NOT_FIND_OPERATOR_CLASS_ERROR);
        }

        /** 2.构建分页信息,分批获取数据并写入 */
        try {
            PageParameter page = new PageParameter();
            int currentPage = 1;
            int pageSize = CommonConstants.ExportConstants.EXPORT_OPERATION_PER_MAX_NUM;
            List<String> contentList = null;
            while (true) {
                // 设置分页对象
                page.setCurrentPage(currentPage);
                page.setPageSize(pageSize);
                dto.setPage(page);
                // 调用实例获取该批次写入的数据
                contentList = operator.operation(dto, CommonConstants.ExportConstants.EXPORT_FILE_SPLIT_SIGN);
                if (contentList != null && contentList.size() > 0) {
                    writeFile(exportFile, contentList);
                }
                if (contentList == null || contentList.size() < pageSize) {
                    break; // 当返回的数据集为null,或者小于每批查询的最大数量时
                }
                currentPage++;
            }
        } catch (Exception ex) {
            logger.error("write export data error", ex);
            throw new ExportOperatorException(ExportOperatorException.WRITE_DATA_ERROR);
        }
    }

    /**
     * 向文件中写入文件头
     * 
     * @param file
     * @param content
     * @throws Exception
     */
    private static void writeFileHead(File file, String content) throws Exception {
        BufferedWriter bw = null;
        try {
            bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file, true),
                    CommonConstants.ExportConstants.EXPORT_FILE_ENCODING));

            bw.write(content);
            bw.write(CommonConstants.ExportConstants.EXPORT_NEW_LINE_SIGN);
        } finally {
            closeBufWriter(bw);
        }
    }

    /**
     * 向文件中追加写入多行数据
     * 
     * @param file
     * @param contentList
     *            多行数据
     * @throws Exception
     */
    private static void writeFile(File file, List<String> contentList) throws Exception {
        BufferedWriter bw = null;
        try {
            bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file, true),
                    CommonConstants.ExportConstants.EXPORT_FILE_ENCODING));

            Iterator<String> iterator = contentList.iterator();
            while (iterator.hasNext()) {
                bw.write(iterator.next());
                bw.write(CommonConstants.ExportConstants.EXPORT_NEW_LINE_SIGN);
            }
        } finally {
            closeBufWriter(bw);
        }
    }

    /**
     * 生成导出文件.
     * 
     * @param type
     *            导出模块类型
     * @return file
     */
    private static File GenerateFile(String type) {
        try {
            /** 1. 文件路径 */
            // SimpleDateFormat defaultDatetimeFormat = new
            // SimpleDateFormat("yyyyMMdd");
            Date date = Calendar.getInstance().getTime();
            String path = CommonConstants.ExportConstants.EXPORT_FILE_PATH
                    + CommonConstants.SysParamConstants.FILE_SEPARATOR;

            /** 2. 生成文件名 */
            String rand = String.valueOf(new Random().nextInt(10000));
            while (rand.length() < 4) {
                rand = "0" + rand;
            }
            // 文件名格式:type+13位时间戳+4位随机码
            String filename = type + date.getTime() + rand + CommonConstants.ExportConstants.EXPORT_FILE_EXTNAME;

            /** 3. 若文件不存在则创建 */
            File dir = new File(path);
            if (!dir.exists()) {
                dir.mkdirs();
            }
            File file = new File(path + filename);
            if (!file.exists()) {
                file.createNewFile();
            }

            return file;
        } catch (Exception ex) {
            logger.error("generate file error", ex);
            throw new ExportOperatorException(ExportOperatorException.CREATE_NEW_FILE_ERROR);
        }
    }

    /**
     * 关闭BufferedWriter.
     * 
     * @param bw
     *            the bw
     */
    private static void closeBufWriter(BufferedWriter bw) {
        try {
            if (bw != null) {
                bw.close();
            }
        } catch (Exception ex) {
            logger.error("close BufferedWriter error.", ex);
        } finally {
            bw = null;
        }
    }

}
